import { db } from "@/db/db";
import { auth } from "@/middlewares/auth";
import { checkSchema, middleware, router } from "@/router/router";
import { utils } from "@/utils";
import { Enum } from "@/share/enums/enum";
import { UserModel } from "@/share/models";
import { UserSignal } from "@/share/signals/index";
import { Like } from "typeorm";
import { UserSchema } from "./$schema";

/**
 * 用户服务类，提供用户相关操作的服务。
 */
export class UserService {
  /**
   * 用户登录接口。
   * 通过用户名和密码进行身份验证，并返回登录成功的用户信息及令牌。
   *
   * @param username 用户名。
   * @param password 密码。
   * @returns 如果登录成功，返回用户信息和令牌；否则返回错误信息。
   */
  @router(UserSignal.Login, "用户登录")
  @checkSchema(UserSchema.Login)
  static async login(c: Context<DTO.User.LoginParams>) {
    const params = c.params;
    const userRepository = db.getRepository(UserModel);
    const user = await userRepository.findOneBy({ username: params.username });
    if (!user) return c.fail("用户名不存在");
    if (utils.md5(params.password) !== user.password) return c.fail("密码不正确");
    // 删除用户对象中的密码属性，避免敏感信息泄露
    delete user.password;
    // 生成用户令牌
    const token = utils.TokenManager.create(user);
    // 设置响应头中的令牌信息
    c.set("x-token", token);

    return c.success(user);
  }

  @router(UserSignal.UpdatePassword, "更新密码")
  @checkSchema(UserSchema.UpdatePassword)
  static async updatePassword(c: Context<DTO.User.UpdatePasswordParams>) {
    const params = c.params;

    // 判断原始密码是否正确
    if (utils.md5(params.originPassword) !== c.user.password) return c.fail("原始密码校验失败");

    // 更新密码
    const userRepository = db.getRepository(UserModel);
    await userRepository.update(c.user.id, { password: utils.md5(params.newPassword) });
    return c.success();
  }

  /**
   * 重置密码
   * @param c
   * @returns
   */
  @router(UserSignal.ResetPassword, "重置密码")
  @middleware(auth(Enum.Role.Admin))
  static async resetPassword(c: Context<DTO.User.ResetPasswordParams>) {
    const params = c.params;

    const userRepository = db.getRepository(UserModel);
    // 判断登录名是否重复
    const user = await userRepository.findOneBy({ id: params.id });
    if (!user) return c.fail("用户名不存在");
    // 重置，默认密码123456
    user.password = utils.md5("123456");
    user.updateBy = c.user.username;
    const savedUser = await userRepository.save(user);
    delete savedUser.password;
    return c.success(savedUser);
  }

  // 用户创建
  @router(UserSignal.CreateUser)
  @middleware(auth(Enum.Role.Admin))
  @checkSchema(UserSchema.CreateUser)
  static async createUser(c: Context<DTO.User.CreateUserParams>) {
    const params = c.params;

    const userRepository = db.getRepository(UserModel);
    // 判断登录名是否重复
    const exists = await userRepository.existsBy({ username: params.username });
    if (exists) return c.fail("该登录名用户已存在");
    // 如果不存在则创建，默认密码123456
    const user = new UserModel();
    user.username = params.username;
    user.nickname = params.nickname;
    user.role = Enum.Role.Normal;
    user.department = params.department;
    user.phone = params.phone;
    user.password = utils.md5("123456");
    user.createBy = c.user.username;
    user.updateBy = c.user.username;
    const savedUser = await userRepository.save(user);
    delete savedUser.password;
    return c.success(savedUser);
  }

  // 删除用户
  @router(UserSignal.DeleteUser)
  @middleware(auth(Enum.Role.Admin))
  @checkSchema(UserSchema.DeleteUser)
  static async deleteUser(c: Context<DTO.User.DeleteUserParams>) {
    const params = c.params;
    const userRepository = db.getRepository(UserModel);
    // 如果是删除自己，则直接退出
    if (params.id === c.user.id) return c.fail("不能删除自己");
    await userRepository.delete(params.id);
    // TODO 删除案件或者转移案件
    return c.success();
  }

  // 批量删除用户
  @router(UserSignal.DeleteUsers)
  @middleware(auth(Enum.Role.Admin))
  @checkSchema(UserSchema.DeleteUsers)
  static async deleteUsers(c: Context<DTO.User.DeleteUsersParams>) {
    const params = c.params;
    const userRepository = db.getRepository(UserModel);
    const ids = params.ids.filter(id => id !== c.user.id);
    await userRepository.delete(ids);
    return c.success();
  }

  /**
   * 更新用户信息的路由处理函数。
   *
   * 该函数通过@router装饰器指定了处理UserSignal.UpdateUser信号的路由，
   * 并通过@middleware装饰器应用了管理员角色的认证中间件，确保只有管理员角色的用户可以调用此功能。
   *
   * @param c 上下文对象，包含请求的参数和方法。其中params属性包含了来自请求的用户ID，nickname和phone信息。
   * @returns 返回处理结果，通常是一个表示操作成功的响应。
   */
  @router(UserSignal.UpdateUser)
  @middleware(auth(Enum.Role.Admin))
  @checkSchema(UserSchema.UpdateUser)
  static async updateUser(c: Context<DTO.User.UpdateUserParams>) {
    // 从上下文中获取请求参数
    const params = c.params;
    // 从数据库实例中获取用户仓库
    const userRepository = db.getRepository(UserModel);
    // 更新指定ID的用户信息，包括昵称和电话号码
    //if (!params.nickname || !params.phone || !params.department) return c.success();
    await userRepository.update(params.id, { nickname: params.nickname, phone: params.phone, department: params.department });
    // const updateColumns: any = [];
    // if (params.nickname) updateColumns.nickname = params.nickname;
    // if (params.phone) updateColumns.phone = params.phone;
    // if (params.department) updateColumns.department = params.department;
    // await userRepository.update(params.id, updateColumns);
    // 返回操作成功的响应
    return c.success();
  }

  /**
   * 获取用户列表的路由处理函数。
   * 通过中间件限制只有管理员角色才能访问此路由。
   *
   * @param c 上下文对象，包含请求和响应的相关信息以及参数。
   * @returns 返回一个包含用户列表、总数量、分页信息的成功响应。
   */
  @router(UserSignal.List)
  @middleware(auth(Enum.Role.Admin))
  @checkSchema(UserSchema.ListUser)
  static async listUser(c: Context<DTO.User.ListUserParams>) {
    // 获取请求参数
    const params = c.params;
    // 获取用户仓库实例，用于数据库操作
    const userRepository = db.getRepository(UserModel);

    // 根据关键词查询符合匹配条件的用户总数
    const count = await userRepository.countBy([
      { nickname: Like(`%${params.keyword}%`) },
      { phone: Like(`%${params.keyword}%`) },
      { username: Like(`%${params.keyword}%`) }
    ]);

    // 根据总数和当前页数调整pageNum，以避免无效的分页请求
    if ((params.pageNum - 1) * params.pageSize > count) {
      params.pageNum = Math.ceil(count / params.pageSize);
    }

    // 查询符合匹配条件的用户列表及总数量，用于分页显示
    const [list, total] = await userRepository.findAndCount({
      skip: (params.pageNum - 1) * params.pageSize,
      take: params.pageSize,
      select: ["id", "username", "nickname", "phone", "role", "department"],
      where: [
        { nickname: Like(`%${params.keyword}%`) },
        { phone: Like(`%${params.keyword}%`) },
        { username: Like(`%${params.keyword}%`) }
      ],
      order: { createTime: "DESC" }
    });

    // 返回查询结果及分页信息
    return c.success({ list, total, pageNum: params.pageNum, pageSize: params.pageSize });
  }
}
